#include "String.h"
#include <math.h>

using namespace std;

ostream& operator <<(ostream& slog, const String& s) {
	slog << (string(s.getBufferRead(), s.length()));
	return slog;
}

void String::maybeCloneSelf(size_t increase) {
	if (!arr.unique() || (count + increase > capcity_)) {
		capcity_ = Max(Max(8, capcity_), (count + increase) * 2);
		char* buf = new char[capcity_];
		if (count && arr.get()) {
			ArrayMove(buf, arr.get(), count); //count * 1
		}
		arr.reset(buf);
	}
}

String::String(const char* s, size_t len)
		: count(0), capcity_(0) {
	if (s && len) {
		copyStr(s, len);
	}
}
String::String(const char* s)
		: count(0), capcity_(0) {
	if (s) {
		copyStr(s, strlen(s));
	}
}
String::String(const string& s)
		: count(0), capcity_(0) {
	copyStr(s.c_str(), s.length());
}

String::String(const String& other)
		: count(0), capcity_(0) {
	copyStr(other.arr.get(), other.count);
}

String::String(size_t capcity)
		: count(0), capcity_(capcity) {
	char* buf = new char[Max(capcity_, 8)];
	arr.reset(buf);
}
String::String()
		: count(0), capcity_(0) {
}
String::~String() {
	arr.reset(0);
}

String& String::operator=(const String& other) {
	copyStr(other.arr.get(), other.count);
	return *this;
}

void String::copyStr(const char* s, size_t len) {
	if (s && len) {
		if (arr.get() && arr.unique() && len <= capcity_) {
			ArrayMove(arr.get(), s, len); //len * 1
			count = len;
		} else {
			capcity_ = Max(len, 4);
			char* buf = new char[capcity_];
			ArrayMove(buf, s, len); //len * 1
			arr.reset(buf);
			count = len;
		}
	} else {
		count = 0;
	}
}
//will delete[] s, when String Objects destructor
void String::manageStr(char* s, size_t len) {
	assert( s);
	arr.reset(s);
	count = len;
	capcity_ = len;
}

void String::replace(size_t from, size_t length, const char* values, size_t valuesCount) {
	if (!length && !valuesCount) { //modify nothing
		return;
	}
	assert(from + length <= count);

	size_t newCount = count - length + valuesCount;
	if (arr.get() && arr.unique() && newCount <= capcity_) {
		ArrayMove(arr.get() + from + valuesCount, arr.get() + from + length, count - from - length);
		ArrayMove(arr.get() + from, values, valuesCount);
	} else {
		size_t newCap = Max(newCount * 2, Max(capcity_, 8));
		char* array = new char[newCap];
		if (arr.get()) {
			ArrayMove(array, arr.get(), from);
		}
		ArrayMove(array + from, values, valuesCount);
		if (arr.get()) {
			ArrayMove(array + from + valuesCount, arr.get() + from + length, count - from - length);
		}
		arr.reset(array);
		capcity_ = newCap;
	}
	count = newCount;

}

String String::subString(size_t from, size_t length) {
	assert(from + length <= count);
	String s(length);
	if (arr.get()) {
		ArrayMove(s.arr.get(), arr.get() + from, length);
	}
	s.count = length;
	return s;

}

String String::subString(size_t from) {
	assert(from <= count);
	if (from == count) {
		return String();
	} else {
		int length = count - from;
		String s(length);
		if (arr.get()) {
			ArrayMove(s.arr.get(), arr.get() + from, length);
		}
		s.count = length;
		return s;
	}
}

bool String::rangeEquals(size_t from, const char* other, size_t len) {
	if (from + len <= length()) {
		if (len) {
			if (other) {
				for (int i = 0; i < len; ++i) {
					if (get(i+from) != other[i]) {
						return false;
					}
				}
				return true;
			} else {
				if (from == length()) {
					return true;
				}
			}
		} else {
			return true;
		}
	}
	return false;
}

bool String::equals(const char* other) {
	if (other == 0) {
		return count == 0;
	} else {
		const char* buf = getBufferRead();
		size_t c = 0;
		while (c < count && other[c]) {
			if (buf[c] != other[c]) {
				return false;
			}
			++c;
		}
		return c == count && other[c] == 0;
	}
}
bool String::startWith(const char* other) {
	if (other == 0) {
		return true;
	} else {
		const char* buf = getBufferRead();
		size_t c = 0;
		while (c < count && other[c]) {
			if (buf[c] != other[c]) {
				return false;
			}
			++c;
		}
		return c <= count && other[c] == 0;
	}
}


